﻿#region

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TvdbLib.Data.Banner;

#endregion

namespace TvdbLib.Data
{
    /// <summary>
    ///     Series class holds all the info that can be retrieved from http://thetvdb.com.  <br />
    ///     <br />
    ///     Those are as follows:<br />
    ///     <br />
    ///     - Base information: <br />
    ///     <code>
    ///         <Series>
    ///             <id>73739</id>
    ///             <Actors>|Malcolm David Kelley|Jorge Garcia|Maggie Grace|...|</Actors>
    ///             <Airs_DayOfWeek>Thursday</Airs_DayOfWeek>
    ///             <Airs_Time>9:00 PM</Airs_Time>
    ///             <ContentRating>TV-14</ContentRating>
    ///             <FirstAired>2004-09-22</FirstAired>
    ///             <Genre>|Action and Adventure|Drama|Science-Fiction|</Genre>
    ///             <IMDB_ID>tt0411008</IMDB_ID>
    ///             <Language>en</Language>
    ///             <Network>ABC</Network>
    ///             <Overview>After Oceanic Air flight 815...</Overview>
    ///             <Rating>8.9</Rating>
    ///             <Runtime>60</Runtime>
    ///             <SeriesID>24313</SeriesID>
    ///             <SeriesName>Lost</SeriesName>
    ///             <Status>Continuing</Status>
    ///             <banner>graphical/24313-g2.jpg</banner>
    ///             <fanart>fanart/original/73739-1.jpg</fanart>
    ///             <lastupdated>1205694666</lastupdated>
    ///             <zap2it_id>SH672362</zap2it_id>
    ///         </Series>
    ///     </code>
    ///     - Banner information <br />
    ///     - Episode information <br />
    ///     - Extended actor information <br />
    ///     <br />
    ///     Each of those can be downloaded seperately. If the information is downloaded as
    ///     zipped file, everything is downloaded at once
    /// </summary>
    [Serializable]
    public class TvdbSeries : TvdbSeriesFields
    {
        #region Fields

        //all banners
        private List<TvdbBanner> m_banners;
        private bool m_bannersLoaded;
        private bool m_isFavorite;
        private Dictionary<TvdbLanguage, TvdbSeriesFields> m_seriesTranslations;

        //Actor Information
        private List<TvdbActor> m_tvdbActors;
        private bool m_tvdbActorsLoaded;

        #endregion Fields

        #region Constructors

        /// <summary>
        ///     Basic constructor for the TvdbSeries class
        /// </summary>
        public TvdbSeries()
        {
            m_banners = new List<TvdbBanner>();
            m_bannersLoaded = false;
            m_tvdbActorsLoaded = false;
        }

        /// <summary>
        ///     Create a series object with all the information contained in the TvdbSeriesFields object
        /// </summary>
        /// <param name="_fields"> </param>
        internal TvdbSeries(TvdbSeriesFields _fields)
            : this()
        {
            AddLanguage(_fields);
            SetLanguage(_fields.Language);
            //UpdateTvdbFields(_fields, true);
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        ///     Formatted String of actors that appear during this episode in the
        ///     format | actor1 | actor2 | actor3 |
        /// </summary>
        public String ActorsString
        {
            get
            {
                if (Actors == null || Actors.Count == 0) return "";
                var retString = new StringBuilder();
                retString.Append("|");
                foreach (String s in Actors)
                {
                    retString.Append(s);
                    retString.Append("|");
                }
                return retString.ToString();
            }
        }

        /// <summary>
        ///     returns a list of all banners for this series
        /// </summary>
        public List<TvdbBanner> Banners
        {
            get { return m_banners; }
            set
            {
                m_banners = value;
                m_bannersLoaded = true;
            }
        }

        /// <summary>
        ///     Is the banner info loaded
        /// </summary>
        public bool BannersLoaded
        {
            get { return m_bannersLoaded; }
            set { m_bannersLoaded = value; }
        }

        /// <summary>
        ///     Returns a list of all fanart banners for this series
        /// </summary>
        public List<TvdbFanartBanner> FanartBanners
        {
            get
            {
                var retList = new List<TvdbFanartBanner>();
                foreach (TvdbBanner b in Banners)
                {
                    if (b.GetType() == typeof (TvdbFanartBanner))
                    {
                        retList.Add((TvdbFanartBanner) b);
                    }
                }
                return retList;
            }
        }

        /// <summary>
        ///     Returns the genre string in the format | genre1 | genre2 | genre3 |
        /// </summary>
        public String GenreString
        {
            get
            {
                if (Genre == null || Genre.Count == 0) return "";
                var retString = new StringBuilder();
                retString.Append("|");
                foreach (String s in Genre)
                {
                    retString.Append(s);
                    retString.Append("|");
                }
                return retString.ToString();
            }
        }

        /// <summary>
        ///     Is the series a favorite
        /// </summary>
        public bool IsFavorite
        {
            get { return m_isFavorite; }
            set { m_isFavorite = value; }
        }

        /// <summary>
        ///     How many Season does the series have
        /// </summary>
        public int NumSeasons
        {
            get
            {
                if (Episodes != null && EpisodesLoaded && Episodes.Count > 0)
                {
                    int maxSeason = 0;
                    foreach (TvdbEpisode e in Episodes)
                    {
                        if (e.SeasonNumber > maxSeason)
                        {
                            maxSeason++;
                        }
                    }
                    return maxSeason;
                }
                else
                {
                    return 0;
                }
            }
        }

        /// <summary>
        ///     Returns a list of all season banners for this series
        /// </summary>
        public List<TvdbPosterBanner> PosterBanners
        {
            get
            {
                var retList = new List<TvdbPosterBanner>();
                foreach (TvdbBanner b in Banners)
                {
                    if (b.GetType() == typeof (TvdbPosterBanner))
                    {
                        retList.Add((TvdbPosterBanner) b);
                    }
                }
                return retList;
            }
        }

        /// <summary>
        ///     Returns a list of all season banners for this series
        /// </summary>
        public List<TvdbSeasonBanner> SeasonBanners
        {
            get
            {
                var retList = new List<TvdbSeasonBanner>();
                foreach (TvdbBanner b in Banners)
                {
                    if (b.GetType() == typeof (TvdbSeasonBanner))
                    {
                        retList.Add((TvdbSeasonBanner) b);
                    }
                }
                return retList;
            }
        }

        /// <summary>
        ///     returns a list of all series banners for this series
        /// </summary>
        public List<TvdbSeriesBanner> SeriesBanners
        {
            get
            {
                var retList = new List<TvdbSeriesBanner>();
                foreach (TvdbBanner b in Banners)
                {
                    if (b.GetType() == typeof (TvdbSeriesBanner))
                    {
                        retList.Add((TvdbSeriesBanner) b);
                    }
                }
                return retList;
            }
        }

        /// <summary>
        ///     List of loaded tvdb actors
        /// </summary>
        public List<TvdbActor> TvdbActors
        {
            get { return m_tvdbActors; }
            set
            {
                m_tvdbActorsLoaded = true;
                m_tvdbActors = value;
            }
        }

        /// <summary>
        ///     Is the actor info loaded
        /// </summary>
        public bool TvdbActorsLoaded
        {
            get { return m_tvdbActorsLoaded; }
            set { m_tvdbActorsLoaded = value; }
        }

        /// <summary>
        ///     Get all available Translations
        /// </summary>
        internal Dictionary<TvdbLanguage, TvdbSeriesFields> SeriesTranslations
        {
            get { return m_seriesTranslations; }
            set { m_seriesTranslations = value; }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        ///     Get all languages that have already been loaded for this series
        /// </summary>
        /// <returns> List of all translations that are loaded for this series </returns>
        public List<TvdbLanguage> GetAvailableLanguages()
        {
            if (m_seriesTranslations != null)
            {
                return m_seriesTranslations.Keys.ToList();
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        ///     Return a list of episodes for the given season
        /// </summary>
        /// <param name="_season"> Season for which episodes should be returned </param>
        /// <returns> List of episodes for the given season </returns>
        public List<TvdbEpisode> GetEpisodes(int _season)
        {
            var retList = new List<TvdbEpisode>();
            if (Episodes != null && Episodes.Count > 0 && EpisodesLoaded)
            {
                foreach (TvdbEpisode e in Episodes)
                {
                    if (e.SeasonNumber == _season)
                    {
                        retList.Add(e);
                    }
                }
            }
            return retList;
        }

        /// <summary>
        ///     Set the language of the series to one of the languages that have
        ///     already been loaded
        /// </summary>
        /// <param name="_language"> The new language for this series </param>
        /// <returns> true if success, false otherwise </returns>
        public bool SetLanguage(TvdbLanguage _language)
        {
            return SetLanguage(_language.Abbriviation);
        }

        /// <summary>
        ///     Set the language of the series to one of the languages that have
        ///     already been loaded
        /// </summary>
        /// <param name="_language"> The new language abbriviation for this series </param>
        /// <returns> true if success, false otherwise </returns>
        public bool SetLanguage(String _language)
        {
            foreach (var kvp in m_seriesTranslations)
            {
                if (kvp.Key.Abbriviation.Equals(_language))
                {
                    UpdateTvdbFields(kvp.Value, true);
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        ///     returns SeriesName (SeriesId)
        /// </summary>
        /// <returns> String representing this series </returns>
        public override string ToString()
        {
            return SeriesName + "(" + Id + ")";
        }

        /// <summary>
        ///     Add a new language to the series
        /// </summary>
        /// <param name="_fields"> </param>
        internal void AddLanguage(TvdbSeriesFields _fields)
        {
            if (m_seriesTranslations == null)
            {
                m_seriesTranslations = new Dictionary<TvdbLanguage, TvdbSeriesFields>();
            }

            //delete translation if it already exists and overwrite it with a new one
            if (m_seriesTranslations.ContainsKey(_fields.Language))
            {
                m_seriesTranslations.Remove(_fields.Language);
            }
            /*foreach (KeyValuePair<TvdbLanguage, TvdbSeriesFields> kvp in m_seriesTranslations)
            {
              if (kvp.Key == _fields.Language)
              {
                m_seriesTranslations.Remove(kvp.Key);
              }
            }*/

            m_seriesTranslations.Add(_fields.Language, _fields);
        }

        internal void SetEpisodes(List<TvdbEpisode> _episodes)
        {
            foreach (var kvp in m_seriesTranslations)
            {
                if (kvp.Key.Abbriviation.Equals(Language.Abbriviation))
                {
                    kvp.Value.EpisodesLoaded = true;
                    kvp.Value.Episodes.Clear();
                    kvp.Value.Episodes.AddRange(_episodes);
                }
            }

            EpisodesLoaded = true;
            Episodes.Clear();
            Episodes.AddRange(_episodes);
        }

        /// <summary>
        ///     Uptdate the info of the current series with the updated one
        /// </summary>
        /// <param name="_series"> TvdbSeries object </param>
        protected void UpdateSeriesInfo(TvdbSeries _series)
        {
            Actors = _series.Actors;
            AirsDayOfWeek = _series.AirsDayOfWeek;
            AirsTime = _series.AirsTime;
            BannerPath = _series.BannerPath;
            Banners = _series.Banners;
            ContentRating = _series.ContentRating;
            FanartPath = _series.FanartPath;
            FirstAired = _series.FirstAired;
            Genre = _series.Genre;
            Id = _series.Id;
            ImdbId = _series.ImdbId;
            Language = _series.Language;
            LastUpdated = _series.LastUpdated;
            Network = _series.Network;
            Overview = _series.Overview;
            Rating = _series.Rating;
            Runtime = _series.Runtime;
            SeriesName = _series.SeriesName;
            Status = _series.Status;
            TvDotComId = _series.TvDotComId;
            Zap2itId = _series.Zap2itId;

            if (_series.EpisodesLoaded)
            {
//check if the old series has any images loaded already -> if yes, save them
                if (EpisodesLoaded)
                {
                    foreach (TvdbEpisode oe in Episodes)
                    {
                        foreach (TvdbEpisode ne in _series.Episodes)
                        {
                            if (oe.SeasonNumber == ne.SeasonNumber &&
                                oe.EpisodeNumber == ne.EpisodeNumber)
                            {
                                if (oe.Banner != null && oe.Banner.IsLoaded)
                                {
                                    ne.Banner = oe.Banner;
                                }
                            }
                        }
                    }
                }

                Episodes.Clear();
                Episodes.AddRange(_series.Episodes);
            }

            if (_series.TvdbActorsLoaded)
            {
//check if the old series has any images loaded already -> if yes, save them
                if (TvdbActorsLoaded)
                {
                    foreach (TvdbActor oa in TvdbActors)
                    {
                        foreach (TvdbActor na in _series.TvdbActors)
                        {
                            if (oa.Id == na.Id)
                            {
                                if (oa.ActorImage != null && oa.ActorImage.IsLoaded)
                                {
                                    na.ActorImage = oa.ActorImage;
                                }
                            }
                        }
                    }
                }
                TvdbActors = _series.TvdbActors;
            }

            if (_series.BannersLoaded)
            {
                //check if the old series has any images loaded already -> if yes, save them
                if (BannersLoaded)
                {
                    foreach (TvdbBanner ob in Banners)
                    {
                        foreach (TvdbBanner nb in _series.Banners)
                        {
                            if (ob.BannerPath.Equals(nb.BannerPath))
                                //I have to check for the banner path since the Update file doesn't include IDs
                            {
                                if (ob.BannerImage != null && ob.IsLoaded)
                                {
                                    nb.BannerImage = ob.BannerImage;
                                }

                                if (ob.GetType() == typeof (TvdbFanartBanner))
                                {
                                    var newFaBanner = (TvdbFanartBanner) nb;
                                    var oldFaBanner = (TvdbFanartBanner) ob;

                                    if (oldFaBanner.ThumbImage != null && oldFaBanner.IsThumbLoaded)
                                    {
                                        newFaBanner.ThumbImage = oldFaBanner.ThumbImage;
                                    }

                                    if (oldFaBanner.ThumbImage != null && oldFaBanner.IsVignetteLoaded)
                                    {
                                        newFaBanner.VignetteImage = oldFaBanner.VignetteImage;
                                    }
                                }
                            }
                        }
                    }
                }
                Banners = _series.Banners;
            }
        }

        #endregion Methods
    }
}